package com.easthome.process.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easthome.auth.service.SysUserService;
import com.easthome.common.result.Result;
import com.easthome.model.process.Process;
import com.easthome.model.process.ProcessRecord;
import com.easthome.model.process.ProcessTemplate;
import com.easthome.model.system.SysUser;
import com.easthome.process.mapper.ProcessMapper;
import com.easthome.process.service.ProcessRecordService;
import com.easthome.process.service.ProcessService;
import com.easthome.process.service.ProcessTemplateService;
import com.easthome.security.custom.LoginUserHelper;
import com.easthome.vo.process.ApprovalVo;
import com.easthome.vo.process.ProcessFormVo;
import com.easthome.vo.process.ProcessQueryVo;
import com.easthome.vo.process.ProcessVo;
import com.easthome.wechat.service.MessageService;

import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.EndEvent;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: 朱敦宇
 * @time: 2023/11/16 11:21
 */
@Service
@Slf4j
public class ProcessServiceImpl extends ServiceImpl<ProcessMapper, Process> implements ProcessService {
    @Override
    public IPage<ProcessVo> getPageList(Page<ProcessVo> processVoPage, ProcessQueryVo vo) {
      IPage<ProcessVo> voIPage =  baseMapper.findPageList(processVoPage,vo);

        return voIPage;
    }
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private ProcessTemplateService processTemplateService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private ProcessRecordService recordService;
    @Autowired
    private MessageService messageService;
    @Override
    public Result startup(ProcessFormVo processFormVo) {
        System.out.println(processFormVo);

        //1.生成一个Process对象
        SysUser sysUser = sysUserService.getById(LoginUserHelper.getUserId().get());
        ProcessTemplate template = processTemplateService.getById(processFormVo.getProcessTemplateId());
        Process process = new Process();
        BeanUtils.copyProperties(processFormVo,process);
        process.setUserId(LoginUserHelper.getUserId().get());
        process.setProcessTemplateId(processFormVo.getProcessTemplateId());
        process.setProcessTypeId(processFormVo.getProcessTypeId());
        process.setCurrentAuditor(sysUser.getName());
        process.setTitle(sysUser.getName()+"发起"+template.getName()+"申请");
        process.setStatus(1);
        process.setProcessCode(System.currentTimeMillis()+"");

        baseMapper.insert(process);
        //2.封装条件  放入流程实例
        Map<String, Object> variables = new HashMap<>();
        JSONObject jsonObject = JSON.parseObject(processFormVo.getFormValues());
        JSONObject formdata = jsonObject.getJSONObject("formData");
        HashMap<String, Object> map = new HashMap<>();
        for (Map.Entry<String, Object> entry : formdata.entrySet()) {
              map.put(entry.getKey(),entry.getValue());
        }
        variables.put("data",map);
        //3.启动一个流程实例   BusinessId工作流与项目表的关联
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(template.getProcessDefinitionKey(), String.valueOf(process.getId()), variables);
        process.setProcessInstanceId(processInstance.getId());
        //4.计算下一个审批人，可能有多个
        List<Task> currentTaskList = this.getCurrentTaskList(processInstance.getId());
        if(!CollectionUtils.isEmpty(currentTaskList)){
            ArrayList<String> assigneeList = new ArrayList<>();
            for (Task task : currentTaskList) {
                SysUser one = sysUserService.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, task.getAssignee()));
                assigneeList.add(one.getName());
                messageService.pushPendingMessage(process.getId(),one.getId(),task.getId());
            }
            process.setCurrentAuditor(StringUtils.join(assigneeList.toArray(),","));
            process.setDescription("等待"+StringUtils.join(assigneeList.toArray(),",")+"审批");
        }
        baseMapper.updateById(process);

        //5.记录操作行为  即ProcessRecord
        recordService.record(process.getId(),1,"发起申请");
        return Result.ok();
    }

    @Override
    public IPage<ProcessVo> findPending(Page<Process> pageParam) {

        List<Task> tasks = taskService.createTaskQuery().taskAssignee(LoginUserHelper.getUserName().get()).listPage((int) ((pageParam.getCurrent() - 1) * pageParam.getSize()), (int) pageParam.getSize());

        List<ProcessVo> processList = new ArrayList<>();
        //根据流程业务Id查询实体并关联
        for (Task task : tasks) {
            String processInstanceId = task.getProcessInstanceId();
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            if(processInstance == null){
                continue;
            }
            String businessKey = processInstance.getBusinessKey();
            if(businessKey == null){
                continue;
            }
            Process process = this.getById(Long.parseLong(businessKey));
            ProcessVo processVo = new ProcessVo();
            BeanUtils.copyProperties(process,processVo);
            processVo.setTaskId(task.getId());
            processList.add(processVo);
        }
        Page<ProcessVo> voPage = new Page<>(pageParam.getCurrent(), pageParam.getSize(), tasks.size());
        processList = processList.stream().sorted(Comparator.comparing(ProcessVo::getCreateTime)).collect(Collectors.toList());
        voPage.setRecords(processList);

        return voPage;
    }
    /**
     * @description: this.process = response.data.process
     *         this.formValues = JSON.parse(this.process.formValues)
     *         this.processRecordList = response.data.processRecordList
     *         this.isApprove = response.data.isApprove
     * @param processId
     */


    @Override
    public Map<String, Object> show(Long processId) {
        HashMap<String, Object> map = new HashMap<>();
        Process process = baseMapper.selectById(processId);
        map.put("process",process);
        LambdaQueryWrapper<ProcessRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProcessRecord::getProcessId,process.getId());
        List<ProcessRecord> processRecordList = recordService.list(wrapper);
        map.put("processRecordList",processRecordList);
        boolean isApprove = false;
        List<Task> currentTaskList = this.getCurrentTaskList(process.getProcessInstanceId());
        if (!CollectionUtils.isEmpty(currentTaskList)) {
            for (Task task : currentTaskList) {
                if (task.getAssignee().equals(LoginUserHelper.getUserName().get())) {
                    isApprove = true;
                }
            }
        }
        map.put("isApprove",isApprove);
        return map;
    }
    /**
     * @description:进行审批  status=1:通过  status = -1 拒绝
     * @param approvalVo
     */
    @Override
    public void approve(ApprovalVo approvalVo) {
        Process process = baseMapper.selectById(approvalVo.getProcessId());
        String taskId = approvalVo.getTaskId();
        Map<String, Object> variables = taskService.getVariables(taskId);
        for (Map.Entry<String, Object> entry : variables.entrySet()) {
            System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
        }
        if(approvalVo.getStatus() == 1){
          //审批通过
            HashMap<String, Object> map = new HashMap<>();
            taskService.complete(taskId,map);
      }
      else {
          //审批不通过
           this.endTask(taskId);
      }
     String description = approvalVo.getStatus().intValue() == 1 ? "已通过" : "驳回";
      //生成任务处理记录
     recordService.record(process.getId(),approvalVo.getStatus(),description);
        List<Task> taskList = this.getCurrentTaskList(process.getProcessInstanceId());
        if(!CollectionUtils.isEmpty(taskList)){
            ArrayList<String> assigneeList = new ArrayList<>();
            log.info(taskList.stream().map(Task::getAssignee).collect(Collectors.toList()).toString());
            for (Task task : taskList) {
                SysUser sysUser = sysUserService.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, task.getAssignee()));

                assigneeList.add(sysUser.getName());
                // TODO推送消息给下一个人
                messageService.pushPendingMessage(process.getId(),sysUser.getId(),task.getId());
            }
            process.setCurrentAuditor(StringUtils.join(assigneeList.toArray(),","));
            process.setDescription("等待"+StringUtils.join(assigneeList.toArray(),",")+"审批");
            process.setStatus(1);
        }else {
            if(approvalVo.getStatus().intValue() == 1){
                process.setDescription("审批完成（同意）");
                process.setStatus(2);
            }else {
                process.setDescription("审批完成（拒绝）");
                process.setStatus(-1);
            }
        }
        messageService.pushProcessedMessage(process.getId(),process.getUserId(),approvalVo.getStatus());
        //更新流程实例信息，即推送消息给申请人
        this.updateById(process);

    }
    @Autowired
    private HistoryService historyService;

    @Override
    public IPage<ProcessVo> findProcessed(Page<Process> pageParam) {
        // 根据当前人的ID查询
        HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery().taskAssignee(LoginUserHelper.getUserName().get()).finished().orderByTaskCreateTime().desc();
        List<HistoricTaskInstance> list = query.listPage((int) ((pageParam.getCurrent() - 1) * pageParam.getSize()), (int) pageParam.getSize());
        long totalCount = query.count();

        List<ProcessVo> processList = new ArrayList<>();
        for (HistoricTaskInstance item : list) {
            String processInstanceId = item.getProcessInstanceId();
            Process process = this.getOne(new LambdaQueryWrapper<Process>().eq(Process::getProcessInstanceId, processInstanceId));
            if(process == null){
                continue;
            }
            ProcessVo processVo = new ProcessVo();
            BeanUtils.copyProperties(process, processVo);
            processVo.setTaskId("0");
            processList.add(processVo);
        }
        IPage<ProcessVo> page = new Page<ProcessVo>(pageParam.getCurrent(), pageParam.getSize(), totalCount);
        processList = processList.stream().sorted(Comparator.comparing(ProcessVo::getCreateTime)).collect(Collectors.toList());
        page.setRecords(processList);
        return page;
    }

    @Override
    public IPage<ProcessVo> findStarted(Page<ProcessVo> pageParam) {
        ProcessQueryVo processQueryVo = new ProcessQueryVo();
        processQueryVo.setUserId(LoginUserHelper.getUserId().get());
        IPage<ProcessVo> page = baseMapper.findPageList(pageParam, processQueryVo);
//        IPage<ProcessVo> page =processMapper.selectPage(pageParam, processQueryVo);
//        processList = processList.stream().sorted(Comparator.comparing(ProcessVo::getCreateTime)).collect(Collectors.toList());
        for (ProcessVo item : page.getRecords()) {
            item.setTaskId("0");
        }
        return page;

    }

    @Autowired
  private RepositoryService repositoryService;
    private void endTask(String taskId) {
        //  当前任务
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();

        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        List endEventList = bpmnModel.getMainProcess().findFlowElementsOfType(EndEvent.class);
        // 并行任务可能为null
        if(CollectionUtils.isEmpty(endEventList)) {
            return;
        }
        FlowNode endFlowNode = (FlowNode) endEventList.get(0);
        FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(task.getTaskDefinitionKey());

        //  临时保存当前活动的原始方向
        List originalSequenceFlowList = new ArrayList<>();
        originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
        //  清理活动方向
        currentFlowNode.getOutgoingFlows().clear();

        //  建立新方向
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId("newSequenceFlowId");
        newSequenceFlow.setSourceFlowElement(currentFlowNode);
        newSequenceFlow.setTargetFlowElement(endFlowNode);
        List newSequenceFlowList = new ArrayList<>();
        newSequenceFlowList.add(newSequenceFlow);
        //  当前节点指向新的方向
        currentFlowNode.setOutgoingFlows(newSequenceFlowList);

        //  完成当前任务
        taskService.complete(task.getId());

    }


    @Autowired
    private TaskService taskService;
    /**
     * @description: 获取当前发起流程实例的任务
     * @param id

     */
    private List<Task> getCurrentTaskList(String id) {
        List<Task> list = taskService.createTaskQuery().processInstanceId(id).list();
        return list;
    }
}
